package com.tools.common.object.json;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.tools.common.exception.ParseRuntimeException;
import com.tools.common.object.C;
import com.tools.common.object.Note;
import com.tools.common.object.ObjKit;

import java.util.Map;

/**
 * 封装 Jackson 的工具类
 * */
@Note("封装 Jackson 的工具类")
public final class JsonKit extends JacksonKit {

    private JsonKit() {}

    @Note("序列化时过滤 null 值的 ObjectMapper。Map 集合中 value 为 null 也会被过滤")
    private static final ObjectMapper NOTNULL = newFilterNullValueMapper();

    @Note("允许序列化后的 JSON 字符串有 null 值的 ObjectMapper")
    private static final ObjectMapper HASNULL = newHasNullValueMapper();

    /* *******************************************************************************************
     *
     *          构建 ObjectMapper 对象
     *
     * *******************************************************************************************
     * */

    @Note("构建过滤 null 值的 ObjectMapper 对象")
    public static ObjectMapper newFilterNullValueMapper() {
        ObjectMapper mapper = new ObjectMapper();
        configMapperFilterNull(mapper);
        configMapperAccessAllField(mapper);
        configMapperSkipUnknownField(mapper);
        configMapperSingleValueAsArray(mapper);
        configMapperCharArrayToArray(mapper);
        configMapperRWByEnumToString(mapper);
        addCustomSerializers(mapper, SerializerHandler.all());
        addCustomDeserializers(mapper, DeserializerHandler.all());
        return mapper;
    }


    @Note("构建不过滤 null 值的 ObjectMapper 对象")
    public static ObjectMapper newHasNullValueMapper() {
        ObjectMapper mapper = new ObjectMapper();
        configMapperAccessAllField(mapper);
        configMapperSkipUnknownField(mapper);
        configMapperCharArrayToArray(mapper);
        configMapperSingleValueAsArray(mapper);
        configMapperRWByEnumToString(mapper);
        addCustomSerializers(mapper, SerializerHandler.all());
        addCustomDeserializers(mapper, DeserializerHandler.all());
        return mapper;
    }

    public static ObjectMapper getNOTNULL() {
        return NOTNULL;
    }

    public static ObjectMapper getHASNULL() {
        return HASNULL;
    }

    public static void addCustomSerializersToNOTNULLMapper(Map<Class, JsonSerializer> serializerMap) {
        addCustomSerializers(NOTNULL, serializerMap);
    }

    public static void addCustomSerializersToHASNULLMapper(Map<Class, JsonSerializer> serializerMap) {
        addCustomSerializers(HASNULL, serializerMap);
    }

    public static void addCustomDeserializersToNOTNULLMapper(Map<Class, StdDeserializer> deserializerMap) {
        addCustomDeserializers(NOTNULL, deserializerMap);
    }

    public static void addCustomDeserializersToHASNULLMapper(Map<Class, StdDeserializer> deserializerMap) {
        addCustomDeserializers(HASNULL, deserializerMap);
    }

    /* *******************************************************************************************
     *
     *          功能方法
     *
     * *******************************************************************************************
     * */

    @Note("将 Java 对象转为 JSON 字符串，过程中过滤 null 值")
    public static String toJSON(Object javaBean) {
        return writeAsJson(NOTNULL, javaBean);
    }

    @Note("将 Java 对象转为 JSON 字符串，如果值为空则照常序列化")
    public static String asJSON(Object javaBean) {
        return writeAsJson(HASNULL, javaBean);
    }


    @Note("运用 Jackson 的流模式转换 JSON 字符串为 Java 对象。" +
            "其中对象类型转为 LinkedHashMap，数组类型转为 ArrayList")
    public static Object toEntity(String json) {
        return parse(json);
    }


    @Note("将 json 反序列化为指定字节码类型的 JavaBean 对象，注意目标类型要有无参构造")
    public static <T> T toEntity(String json, Class<T> entityType) {
        T entity;
        try{
            entity = NOTNULL.readValue(json, entityType);
        } catch (Exception e) {
            String info = (entityType == null) ? null : entityType.getName();
            throw new ParseRuntimeException(e, "目标 JSON 字符串 【" + json + "】 无法转换为 Java 对象 【" + info + "】 ");
        }
        return entity;
    }


    @Note("将 json 反序列化为指定字节码类型的 JavaBean 对象，注意目标类型要有无参构造")
    public static <T> T toEntity(String json, TypeReference<T> entityType) {
        T entity;
        try{
            entity = NOTNULL.readValue(json, entityType);
        } catch (Exception e) {
            String info = (entityType == null) ? null : entityType.getType().getTypeName();
            throw new ParseRuntimeException(e, "目标 JSON 字符串 【" + json + "】 无法转换为 Java 对象 【" + info + "】 ");
        }
        return entity;
    }


    @Note("将 json 反序列化为指定字节码类型的 JavaBean 对象")
    public static <T> T toEntity(String json, C<T> entityType) {
        if(json == null) return null;
        return (T) ObjKit.jsonParserToRealValue(json, entityType);
    }
}
